﻿using System;
using System.Web.UI;
using System.Web.UI.WebControls;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.WebControls;

namespace Eneta.Portal.FeedAggregator
{
    [CLSCompliant(false)]
    public class FeedAggregatorJobManager : Page
    {
        protected enum SchduleTypes
        {
            Minutely,
            Hourly,
            Daily,
            Weekly
        }
        protected Label lblTest;
        protected Literal ErrorMessageLiteral;
        protected WebApplicationSelector WebAppSelector;
        
        protected DropDownList ddAggregatorList;
        protected DropDownList ddAggregatorFeedList;
        protected DropDownList ddFeedItemCacheList;
        protected RadioButtonList rblJobEnabled;
        protected DropDownList ddWebs;

        protected DropDownList ddScheduleType;        
        protected DropDownList ddMinuteInterval;
        protected DropDownList ddDailyHour;
        protected DropDownList ddDailyMinute;
        protected DropDownList ddWeeklyHour;
        protected DropDownList ddWeeklyMinute;
        protected DropDownList ddWeeklyDay;
        protected Panel pnlMinuteInterval;
        protected Panel pnlHourlySchedule;
        protected Panel pnlDailySchedule;
        protected Panel pnlWeeklySchedule;

        private FeedAggregatorJobSettings _settings;
        private FeedAggregatorJobSettings Settings
        {
            get
            {
                try
                {
                    if (_settings == null)
                    {
                        _settings = WebAppSelector.CurrentItem.GetChild<FeedAggregatorJobSettings>(Globals.FeedAggregatorJobSettingsId);
                        if (_settings == null)
                        {
                            SPPersistedObject parent = WebAppSelector.CurrentItem;
                            _settings = new FeedAggregatorJobSettings(Globals.FeedAggregatorJobSettingsId, parent, Guid.NewGuid());
                            _settings.Update();
                        }
                    }
                    return _settings;
                }
                catch
                {
                    ErrorMessageLiteral.Text = @"A new storage location had to be created. Please go back to the Application Management 
      page and come back in before doing any work.";
                    return null;
                }
            }
        }
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            ddWebs.SelectedIndexChanged += ddWebs_SelectedIndexChanged;
        }

        void ddWebs_SelectedIndexChanged(object sender, EventArgs e)
        {
            ErrorMessageLiteral.Text += ddWebs.SelectedValue + "<br/>";
            InitListSelectors();
        }
        protected override void OnLoad(EventArgs e)
        {
            ddWebs.AutoPostBack = true;

            SPContext.Current.Web.AllowUnsafeUpdates = true;

            if (!Page.IsPostBack)
            {
                ddScheduleType.Items.Add(SchduleTypes.Minutely.ToString());
                ddScheduleType.Items.Add(SchduleTypes.Hourly.ToString());
                ddScheduleType.Items.Add(SchduleTypes.Daily.ToString());
                ddScheduleType.Items.Add(SchduleTypes.Weekly.ToString());

                ddWeeklyDay.Items.Add(DayOfWeek.Monday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Tuesday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Thursday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Wednesday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Friday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Saturday.ToString());
                ddWeeklyDay.Items.Add(DayOfWeek.Sunday.ToString());

                for (int i = 1; i < 60; i++)
                {
                    if (i < 25)
                    {
                        ddDailyHour.Items.Add((i - 1).ToString());
                        ddWeeklyHour.Items.Add((i - 1).ToString());
                    }
                    ddMinuteInterval.Items.Add(i.ToString());
                    ddDailyMinute.Items.Add(i.ToString());
                    ddWeeklyMinute.Items.Add(i.ToString());
                }

                pnlHourlySchedule.Visible = true;
            }

        }
        private void BindWebs()
        {
            try
            {
                ddWebs.ClearSelection();
                ddWebs.Items.Clear();

                foreach (SPSite site in WebAppSelector.CurrentItem.Sites)
                    foreach (SPWeb web in site.AllWebs)
                    {
                        var li = new ListItem();
                        var parts = web.Url.Replace("http://", "").Replace("https://", "").Split("/".ToCharArray(), 2);
                        if (parts.Length < 2)
                            li.Text = "/";
                        else
                            li.Text = parts[1];
                        li.Value = web.ID.ToString();
                        ddWebs.Items.Add(li);
                    }

                if (Settings != null)
                    if (ddWebs.Items.FindByValue(Settings.AggregatorListWeb.ToString()) != null)
                        ddWebs.SelectedValue = Settings.AggregatorListWeb.ToString();
            }
            catch (Exception ex)
            {
                ErrorMessageLiteral.Text += ex.ToString();
            }
        }

        protected void WebAppSelector_OnContextChange(object sender, EventArgs e)
        {
            // Clear setting's cache
            _settings = null;
            if(!IsPostBack)
                BindWebs();

            InitListSelectors();            

            // Try to get the settings out for the job and init the drop-down.
            bool jobEnabled = false;
            foreach (SPJobDefinition job in WebAppSelector.CurrentItem.JobDefinitions)
            {
                if (job.Title == Globals.JobName)
                {
                    jobEnabled = !job.IsDisabled;
                    BindFromSchedule(job.Schedule);
                    //TODO: Fill schedule values based on the current job
                    //IntervalMinutesDropDownList.Items.FindByValue(((SPMinuteSchedule)job.Schedule).Interval.ToString()).Selected = true;
                    break;
                }
            }
            rblJobEnabled.SelectedValue = jobEnabled ? "Enabled" : "Disabled";
        }

        private void InitListSelectors()
        {
            //TODO: How to determine Job's SPSite and SPWeb for selected web application?
            //SPWeb spWeb = WebAppSelector.CurrentItem.Sites[0].RootWeb;
            SPSite site;
            SPWeb spWeb;

            try
            {
                site = WebAppSelector.CurrentItem.Sites[0];
                spWeb = site.AllWebs[new Guid(ddWebs.SelectedValue)];
            }
            catch (Exception ex)
            {
                ErrorMessageLiteral.Text += ex + "<br/>";
                return;
            }
            if (spWeb == null)
            {
                ErrorMessageLiteral.Text += "Cannot find web!<br/>";
                return;
            }
            ErrorMessageLiteral.Text += "web: " + spWeb.Url + "<br/>";
            ddAggregatorList.ClearSelection();
            ddFeedItemCacheList.ClearSelection();
            ddAggregatorFeedList.ClearSelection();

            ddAggregatorList.DataTextField = ddAggregatorFeedList.DataTextField =
                                             ddFeedItemCacheList.DataTextField = "Title";
            ddAggregatorList.DataValueField = ddAggregatorFeedList.DataValueField =
                                                   ddFeedItemCacheList.DataValueField = "ID";

            ddAggregatorList.DataSource = ddAggregatorFeedList.DataSource =
                                          ddFeedItemCacheList.DataSource = spWeb.Lists;
            
            ddAggregatorList.DataBind();
            ddFeedItemCacheList.DataBind();
            ddAggregatorFeedList.DataBind();

            if (Settings != null)
            {
                if (ddAggregatorList.Items.FindByValue(Settings.AggregatorListGuid.ToString()) != null)
                    ddAggregatorList.SelectedValue = Settings.AggregatorListGuid.ToString();
                if (ddAggregatorFeedList.Items.FindByValue(Settings.AggregatorFeedListGuid.ToString()) != null)
                    ddAggregatorFeedList.SelectedValue = Settings.AggregatorFeedListGuid.ToString();
                if (ddFeedItemCacheList.Items.FindByValue(Settings.FeedItemsCacheListGuid.ToString()) != null)
                    ddFeedItemCacheList.SelectedValue = Settings.FeedItemsCacheListGuid.ToString();
            }
        }

        protected void ScheduleType_SelectedIndexChanged(object sender, EventArgs e)
        {
            //TODO: Handle schedule type change
            HideAllScheduleSettingsPanels();

            SchduleTypes type = (SchduleTypes)Enum.Parse(typeof(SchduleTypes), ddScheduleType.SelectedValue, true);
            switch (type)
            {
                case SchduleTypes.Minutely:
                    pnlMinuteInterval.Visible = true;
                    break;

                case SchduleTypes.Hourly:
                    pnlHourlySchedule.Visible = true;
                    break;

                case SchduleTypes.Daily:
                    pnlDailySchedule.Visible = true;
                    break;

                case SchduleTypes.Weekly:
                    pnlWeeklySchedule.Visible = true;
                    break;
            }
        }

        private void HideAllScheduleSettingsPanels()
        {
            pnlMinuteInterval.Visible = false;
            pnlHourlySchedule.Visible = false;
            pnlWeeklySchedule.Visible = false;
            pnlDailySchedule.Visible = false;
        }

        protected void SetTimerJobsButton_OnClick(object sender, EventArgs e)
        {
            // Create a new instance of the job and schedule it.
            SPSchedule schedule = CreateScedule((SchduleTypes)Enum.Parse(typeof(SchduleTypes), 
                                                                              ddScheduleType.SelectedValue, true));
            if (schedule == null)
            {
                ErrorMessageLiteral.Text = "Unknown schedule type";
                return;
            }

            // Delete the job for the current Web application.
            foreach (SPJobDefinition oldJob in WebAppSelector.CurrentItem.JobDefinitions)
            {
                if (oldJob.Title == Globals.JobName) { oldJob.Delete(); }
            }

            var aggregatorJob = new FeedAggregatorTimerJob(Globals.JobName, WebAppSelector.CurrentItem);
            aggregatorJob.Schedule = schedule;
            aggregatorJob.IsDisabled = rblJobEnabled.SelectedValue == "Enabled" ? false : true;
            aggregatorJob.Update();            

            // Update settings.
            Settings.AggregatorFeedListGuid = new Guid(ddAggregatorFeedList.SelectedValue);
            Settings.AggregatorListGuid = new Guid(ddAggregatorList.SelectedValue);
            Settings.FeedItemsCacheListGuid = new Guid(ddFeedItemCacheList.SelectedValue);
            Settings.AggregatorListWeb = new Guid(ddWebs.SelectedValue);
            Settings.Update();
        }

        #region Schedule types
        private void BindFromSchedule(SPSchedule schedule)
        {
            if (schedule is SPMinuteSchedule)
            {
                var minSchedule = (SPMinuteSchedule)schedule;
                pnlMinuteInterval.Visible = true;
                ddMinuteInterval.SelectedValue = minSchedule.Interval.ToString();
                ddScheduleType.SelectedValue = SchduleTypes.Minutely.ToString();
            }
            else if (schedule is SPHourlySchedule)
            {
                var hrlSchedule = (SPHourlySchedule)schedule;
                pnlHourlySchedule.Visible = true;
                ddScheduleType.SelectedValue = SchduleTypes.Hourly.ToString();
            }
            else if (schedule is SPDailySchedule)
            {
                var dlySchedule = (SPDailySchedule)schedule;
                pnlDailySchedule.Visible = true;
                ddDailyHour.SelectedValue = dlySchedule.BeginHour.ToString();
                ddDailyMinute.SelectedValue = dlySchedule.BeginMinute.ToString();
                ddScheduleType.SelectedValue = SchduleTypes.Daily.ToString();
            }
            else if (schedule is SPWeeklySchedule)
            {
                var wklSchedule = (SPWeeklySchedule)schedule;
                pnlWeeklySchedule.Visible = true;
                ddWeeklyHour.SelectedValue = wklSchedule.BeginHour.ToString();
                ddWeeklyMinute.SelectedValue = wklSchedule.BeginMinute.ToString();
                ddWeeklyDay.SelectedValue = wklSchedule.BeginDayOfWeek.ToString();
                ddScheduleType.SelectedValue = SchduleTypes.Weekly.ToString();
            }
        }

        private SPSchedule CreateScedule(SchduleTypes type)
        {
            switch (type)
            {
                case SchduleTypes.Minutely:
                    var minSchedule = new SPMinuteSchedule();
                    minSchedule.BeginSecond = 0;
                    minSchedule.EndSecond = 59;
                    minSchedule.Interval = Convert.ToInt32(ddMinuteInterval.SelectedValue);
                    return minSchedule;

                case SchduleTypes.Hourly:
                    var hrlSchedule = new SPHourlySchedule();
                    hrlSchedule.BeginMinute = 0;
                    hrlSchedule.EndMinute = 5;
                    return hrlSchedule;

                case SchduleTypes.Daily:
                    var dlySchedule = new SPDailySchedule();
                    dlySchedule.BeginHour = dlySchedule.EndHour = Convert.ToInt32(ddDailyHour.SelectedValue);
                    dlySchedule.BeginMinute = dlySchedule.EndMinute = Convert.ToInt32(ddDailyMinute.SelectedValue);
                    dlySchedule.BeginSecond = 0;
                    dlySchedule.EndSecond = 59;
                    return dlySchedule;

                case SchduleTypes.Weekly:
                    var wklSchedule = new SPWeeklySchedule();
                    wklSchedule.BeginDayOfWeek = wklSchedule.EndDayOfWeek =
                                                 (DayOfWeek)Enum.Parse(typeof(DayOfWeek), ddWeeklyDay.SelectedValue);
                    wklSchedule.BeginHour = wklSchedule.EndHour = Convert.ToInt32(ddWeeklyHour.SelectedValue);
                    wklSchedule.BeginMinute = wklSchedule.EndMinute = Convert.ToInt32(ddWeeklyMinute.SelectedValue);
                    wklSchedule.BeginSecond = 0;
                    wklSchedule.EndSecond = 59;
                    return wklSchedule;

                default:                    
                    return null;
            }
        }
        #endregion
    }
}